import json
from sqlalchemy.orm import Session
from core.response import resp_500
from core.logger import logger
from app.monitor_metrics.models.prom_alarm_rule import PromAlarmRule
from app.monitor_metrics.models.prom_alarm_group import PromAlarmGroup
from app.monitor_metrics.models.prom_alarm_metrics import PromAlarmMetrics
from app.monitor_metrics.handlers.prom_alarm_set_handler import PromAlarmSetHandler
from app.audit.handlers.audit_event_handler import AuditEventHandler
from common.utils import CommonTimeUtils

class PromAlarmRuleHandler():
    """  PromAlarmRule Handler
    """
    def __init__(self):
        self.prom_alarm_set_handler = PromAlarmSetHandler()


    def get_alarm_rule_search(self, db: Session, page: int, per_page: int, field: str, value: str):
        """
        根据表字段模糊匹配，获取告警规则信息
        """
        try:
            field_info = {field: value}
            order_info = {"classes": "asc", "name": "asc"}
            result = PromAlarmRule.filter_by_field_search(db, page, per_page, field_info, order_info)
            if not result:
                logger.warning(f"get alarm rule search, result is null => {field}:{value}")
                return False, None

            # 过滤内部标签
            for rule in result["items"]:
                rule["labels"] = {
                    key: value
                    for key, value in rule["labels"].items()
                    if not key.startswith("i_")
                }
                rule["annotations"] = {
                    key: value
                    for key, value in rule["annotations"].items()
                    if key not in ["value", "message"]
                }
        except Exception as e:
            message = f"get alarm rule search by {field}:{value} error"
            logger.exception(f"{message} => {e}")
            return resp_500(message)

        return True, result



    def get_alarm_rule_match(self, db: Session, page: int, per_page: int, field: str, value: str):
        """
        根据表字段完全匹配，获取告警规则信息
        """
        try:
            result = PromAlarmRule.filter_by_field_match(db, page, per_page, {field: value})
            if not result:
                logger.warning(f"get alarm rule match failed, result is null => {field}:{value}")
                return False

            # 过滤内部标签
            for rule in result["items"]:
                rule["labels"] = {
                    key: value
                    for key, value in rule["labels"].items()
                    if not key.startswith("i_")
                }
                rule["annotations"] = {
                    key: value
                    for key, value in rule["annotations"].items()
                    if key not in ["value", "message"]
                }
        except Exception as e:
            message = f"get alarm rule match by {field}:{value} error"
            logger.exception(f"{message} => {e}")
            return resp_500(message)

        return result



    def add_alarm_rule(self, db: Session, data: dict):
        """
        创建告警规则， 满足api调用时，实时更新到prometheus
        """
        try:
            # 添加到数据
            result = self.add_alarm_rule_to_database(db, data)
            if not result:
                logger.error(f"add alarm rule to database failed")
                return False

            # 推送到prometheus rule
            alarm_group_info = PromAlarmGroup.get_object_info_by_uuid(db, data["alarm_group_uuid"])
            result = self.prom_alarm_set_handler.alarm_set_sync_prometheus_rule(db, alarm_group_info["alarm_set_uuid"])
            if not result:
                # 推送失败，清理数据
                alarm_rule_info = PromAlarmRule.get_object_info_by_name(db, data["name"])
                self.delete_alarm_rule_to_database(db, alarm_rule_info)

                logger.error(f"add_alarm_rule: update prometheus rule failed")
                return False
            
            # 推送到事件审计
            self.push_to_audit_event(db, "add_alarm_rule", data)
        except Exception as e:
            message = f"add alarm rule error"
            logger.exception(f"{message} data:{data} => {e}")
            return resp_500(message)
        return True


    def add_alarm_rule_to_database(self, db: Session, data: dict):
        """
        创建告警规则到数据库
        """
        try:
            alarm_rule_object = PromAlarmRule.get_object_by_name(db, data["name"])
            if alarm_rule_object:
                # 如果存在， 则异常返回
                logger.error(f"add alarm rule failed, name:{data['name']} was exist")
                return False

            # 检查告警组uuid
            alarm_group_object = PromAlarmGroup.get_object_by_uuid(db, data["alarm_group_uuid"])
            if not alarm_group_object:
                logger.error(f"add alarm rule failed, alarm_group_uuid:{data['alarm_group_uuid']} not exist")
                return False

            # 检查告警指标uuid
            alarm_metrics_object = PromAlarmMetrics.get_object_by_uuid(db, data["alarm_metrics_uuid"])
            if not alarm_metrics_object:
                logger.error(f"add alarm rule failed, alarm_metrics_uuid:{data['alarm_metrics_uuid']} not exist")
                return False

            # 组装数据写到数据库
            data["classes"] = alarm_group_object.classes
            data["labels"]["i_classes"] = data["classes"]
            data["labels"]["i_target"] = data["target"]
            data["labels"]["i_level"] = data["level"]
            data["labels"]["i_notice_teams_uuid"] = json.dumps(data["notice_teams_uuid"])
            data["labels"]["i_notice_count"] = str(data["notice_count"])
            data["labels"]["i_maintain_begin"] = CommonTimeUtils.strftime(data["maintain_begin"])
            data["labels"]["i_maintain_end"] = CommonTimeUtils.strftime(data["maintain_end"])
            data["labels"]["i_maintain_repeat"] = str(data["maintain_repeat"])
            data["labels"]["i_callback"] = data["callback"]
            data["annotations"]["value"] = "{{ $value }} " + data['operator'] + data['value']
            data['annotations'].update(alarm_metrics_object.annotations)
            result = PromAlarmRule.add(db, data)
            if not result:
                logger.error(f"add alarm rule to database failed")
                return False
        except Exception as e:
            logger.exception(f"add alarm rule error => {e}")
            return False

        return True




    def update_alarm_rule(self, db: Session, data: dict):
        """
        更新告警规则， 满足api调用时，实时更新到prometheus
        """
        try:
            alarm_rule_object = PromAlarmRule.get_object_by_uuid(db, data["uuid"])
            if not alarm_rule_object:
                # 如果不存在， 则异常返回
                logger.error(f"update alarm rule failed, alarm_rule_uuid:{data['uuid']} not exist")
                return False

            # 预先保存好之前的数据，方便后续同步失败时，回滚数据库中的数据
            old_alarm_rule_info = PromAlarmRule.get_object_info_by_uuid(db, data["uuid"])

            # 更新到数据库
            result = self.update_alarm_rule_to_database(db, data)
            if not result:
                logger.error(f"update alarm rule to database failed")
                return False

            # 推送到prometheus rule
            alarm_group_info = PromAlarmGroup.get_object_info_by_uuid(db, old_alarm_rule_info["alarm_group_uuid"])
            result = self.prom_alarm_set_handler.alarm_set_sync_prometheus_rule(db, alarm_group_info["alarm_set_uuid"])
            if not result:
                # 推送失败，还原数据
                old_alarm_rule_info.pop("alarm_group")
                old_alarm_rule_info.pop("notice_teams_name")
                self.update_alarm_rule_to_database(db, data)

                logger.error(f"update_alarm_rule: update prometheus rule failed")
                return False
            
            # 推送到事件审计
            self.push_to_audit_event(db, "update_alarm_rule", data)
        except Exception as e:
            message = f"update alarm rule error "
            logger.exception(f"{message} data:{data} => {e}")
            return resp_500(message)
        return True



    def update_alarm_rule_to_database(self, db: Session, data: dict):
        """
        修改告警规则信息到数据库
        """
        try:
            alarm_rule_object = PromAlarmRule.get_object_by_uuid(db, data["uuid"])
            if not alarm_rule_object:
                # 如果不存在， 则异常返回
                logger.error(f"update alarm rule failed, alarm_rule_uuid:{data['uuid']} not exist")
                return False

            # 检查告警指标uuid
            alarm_metrics_object = PromAlarmMetrics.get_object_by_uuid(db, data["alarm_metrics_uuid"])
            if not alarm_metrics_object:
                logger.error(f"update alarm rule failed, alarm_metrics_uuid:{data['alarm_metrics_uuid']} not exist")
                return False

            # 更新告警规则
            data["labels"]["i_classes"] = alarm_rule_object.classes
            data["labels"]["i_target"] = data["target"]
            data["labels"]["i_level"] = data["level"]
            data["labels"]["i_notice_teams_uuid"] = json.dumps(data["notice_teams_uuid"])
            data["labels"]["i_notice_count"] = str(data["notice_count"])
            data["labels"]["i_maintain_begin"] = CommonTimeUtils.strftime(data["maintain_begin"])
            data["labels"]["i_maintain_end"] = CommonTimeUtils.strftime(data["maintain_end"])
            data["labels"]["i_maintain_repeat"] = str(data["maintain_repeat"])
            data["labels"]["i_callback"] = data["callback"]
            data["annotations"]["value"] = "{{ $value }} " + data['operator'] + data['value']
            data['annotations'].update(alarm_metrics_object.annotations)
            result = PromAlarmRule.update(db, data)
            if not result:
                logger.error(f"update alarm rule to database failed")
                return False
        except Exception as e:
            logger.exception(f"update alarm rule to database error => {e}")
            return False

        return True



    def delete_alarm_rule(self, db: Session, data: dict):
        """
        满足api调用时，实时更新到prometheus
        """
        try:
            alarm_rule_object = PromAlarmRule.get_object_by_uuid(db, data["uuid"])
            if not alarm_rule_object:
                # 如果不存在， 则异常返回
                logger.error(f"delete alarm rule failed, uuid:{data['uuid']} not exist")
                return False

            # 预先保存好之前的数据，方便后续同步失败时，回滚数据库中的数据
            old_alarm_rule_info = PromAlarmRule.get_object_info_by_uuid(db, data["uuid"])

            # 更新数据库
            result = self.delete_alarm_rule_to_database(db, data)
            if not result:
                logger.error(f"delete alarm rule to database failed")
                return False

            # 推送到prometheus rule
            alarm_group_info = PromAlarmGroup.get_object_info_by_uuid(db, old_alarm_rule_info["alarm_group_uuid"])
            result = self.prom_alarm_set_handler.alarm_set_sync_prometheus_rule(db, alarm_group_info["alarm_set_uuid"])
            if not result:
                # 推送失败，还原数据
                old_alarm_rule_info.pop("alarm_group")
                old_alarm_rule_info.pop("notice_teams_name")
                self.add_alarm_rule_to_database(db, old_alarm_rule_info)

                logger.error(f"delete_alarm_rule: update prometheus rule failed")
                return False
            
            # 推送到事件审计
            self.push_to_audit_event(db, "delete_alarm_rule", data)
        except Exception as e:
            message = f"delete alarm rule error"
            logger.exception(f"{message} data:{data} => {e}")
            return resp_500(message)

        return True


    def delete_alarm_rule_to_database(self, db: Session, data: dict):
        """
        删除告警规则信息
        """
        try:
            alarm_rule_object = PromAlarmRule.get_object_by_uuid(db, data['uuid'])
            if not alarm_rule_object:
                # 如果不存在， 则异常返回
                logger.error(f"delete alarm rule failed, uuid:{data['uuid']} not exist")
                return False

            # 删除告警指标
            PromAlarmRule.delete_object_by_uuid(db, data['uuid'])
        except Exception as e:
            logger.exception(f"delete alarm rule to database error => {e}")
            return False

        return True


    def push_to_audit_event(self, db: Session, event_name: str, data: dict):
        audit_event_handler = AuditEventHandler()
        event_data = {
            "event_name": event_name,
            "event_type": "monitor_metrics",
            "is_notice": True,
            "comment": str(data)
        }
        audit_event_handler.add_audit_event(db, event_data)
        return True

